import { ARGS_METADATA } from './constants';

export enum ParamTypes {
  BODY = 'BODY',
  QUERY = 'QUERY',
  PATH = 'PATH',
  HEADER = 'HEADER',
  FORM_DATA = 'FORM_DATA',
}

export function assignMetadata<
  TParamType extends keyof typeof ParamTypes,
  TArgs = any
>(args: TArgs, paramType: TParamType, index: number, property?: string) {
  return {
    ...args,
    [`${paramType}:${index}`]: {
      property,
      index,
    },
  };
}

function createParamDecorator(paramType: ParamTypes) {
  return (property?: string): ParameterDecorator => (target, key, index) => {
    const args =
      Reflect.getMetadata(ARGS_METADATA, target.constructor, key) || {};
    Reflect.defineMetadata(
      ARGS_METADATA,
      assignMetadata(args, paramType, index, property),
      target.constructor,
      key,
    );
  };
}

export const Body = (property?: string) =>
  createParamDecorator(ParamTypes.BODY)(property);

export const Query = (property?: string) =>
  createParamDecorator(ParamTypes.QUERY)(property);

export const Path = (property: string) =>
  createParamDecorator(ParamTypes.PATH)(property);

export const Header = (property?: string) =>
  createParamDecorator(ParamTypes.HEADER)(property);

export const FormData = (property?: string) =>
  createParamDecorator(ParamTypes.FORM_DATA)(property);
